package cn.edu.nju.newsFeed;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import cn.edu.nju.R;
import cn.edu.nju.storage.StoreDataProvider;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextWatcher;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

public class WritePostActivity extends Activity {
	public static final String POST_MODE = "post_mode";
	public static final String POST_TAGS = "post_tags";
	public static final int FEED_MODE = 0;
	public static final int COMMENT_MODE = 1;
	private final int FILE_PICTURE = 1;
	private final int CAMERA_PICTURE = 0;
	private final int GET_TAGS = 3;
	private final int IMAGE_SIZE = 100;
	private int mode;
	private int position; // the position of feedItem in the news feed list, used only in comment mode
	private InputMethodManager inputManager;
	private EmotionAdapter emotionAdapter;
	private GridView emotionPanel;
	private LinearLayout imagePanel;
	private EditText editText;
	private AlertDialog.Builder pictureUploadDialog;
	private AlertDialog.Builder timeChooseDialog;
	private DatePicker datePicker;
	private Calendar selectedDate; // save time of this post
	private Uri currentTempImageUri;
	private List<File> sourceImage = new LinkedList<File>();
	private List<Bitmap> previewImage = new LinkedList<Bitmap>();
	private String[] emotions;
	private ArrayList<String> tags = new ArrayList<String>();	
	private PostSender postSender;
	private List<ImageSpan> imageSpans = new ArrayList<ImageSpan>();
	
	@Override
    public void onCreate(Bundle savedInstanceState) {
		requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.write_post);
        Intent intent = getIntent();
        mode = intent.getIntExtra(WritePostActivity.POST_MODE, COMMENT_MODE);
        
        inputManager = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 
        
        
        initEditText();
        initWritePostTitle();
        initCancelButton();
        initSendButton();
        initEmotionFunction();
        initKeyboardButton();

        long userId = StoreDataProvider.getInstance(this).getUserId();
        if(mode == FEED_MODE){
        	postSender = new PostSender(this, FEED_MODE, userId);
        	initPictureFunction();
            initTimeFunction();
            initTagButton();
        }
        else{
        	postSender = new PostSender(this, COMMENT_MODE, userId);
        	position = intent.getIntExtra(NewsFeedActivity.FEED_ITEM_POSITION, 0);       	
        }
	}
	
	private void initEditText(){
		editText = (EditText)findViewById(R.id.share_post_input);
		editText.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				// show soft keyboard and hide emotion panel
				emotionPanel.setVisibility(View.GONE);
				inputManager.showSoftInput(editText, 0);
			}
		});
		editText.addTextChangedListener(new TextWatcher() {
			public void onTextChanged(CharSequence s, int start, int before, int count) {
				// re-scan the edit text and change the emotion
				// clear all existing image spans			
				for(ImageSpan imageSpan : imageSpans){
					editText.getText().removeSpan(imageSpan);
				}
				Spannable spans = (Spannable)editText.getText();	
				String text = editText.getText().toString();
				ImageSpan imageSpan;
				ForegroundColorSpan contentSpan = new ForegroundColorSpan(getResources().getColor(R.color.black));
				boolean hasPureText = false;
				
				// convert emotion string to emotion image
				int startIndex = 0;
				String emotionName;
				Pattern emotionPattern = Pattern.compile("\\[.+?\\]");
				Matcher emotionMatcher = emotionPattern.matcher(text);
				boolean matchResult = emotionMatcher.find();
				while(matchResult){
					if(startIndex < emotionMatcher.start()){
						spans.setSpan(CharacterStyle.wrap(contentSpan), startIndex, emotionMatcher.start(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
						hasPureText = true;
					}
					
					// avoid empty '[]'
					if(emotionMatcher.end() - emotionMatcher.start() > 2){ 
						emotionName = text.substring(emotionMatcher.start() + 1, emotionMatcher.end() - 1);
						Drawable emotionDrawable;
						try {
							emotionDrawable = Drawable.createFromStream(getAssets().open("emotion/" + emotionName + ".png"), null);
							emotionDrawable.setBounds(0, 0, 33, 33);
							if(hasPureText){
								imageSpan = new ImageSpan(emotionDrawable, ImageSpan.ALIGN_BASELINE);
							}
							else{
								imageSpan = new ImageSpan(emotionDrawable, ImageSpan.ALIGN_BOTTOM);
							}
							spans.setSpan(imageSpan, emotionMatcher.start(), emotionMatcher.end(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
							imageSpans.add(imageSpan);
						} catch (IOException e) {
							spans.setSpan(CharacterStyle.wrap(contentSpan), emotionMatcher.start(), emotionMatcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
							hasPureText = true;
						}										
					}
					else{
						spans.setSpan(CharacterStyle.wrap(contentSpan), emotionMatcher.start(), emotionMatcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
						hasPureText = true;
					}
					
					startIndex = emotionMatcher.end();
					matchResult = emotionMatcher.find();
				}
				
				// if there are remaining text
				if(startIndex < text.length()){
					spans.setSpan(contentSpan, startIndex, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
				}
			}
			
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
				// TODO Auto-generated method stub			
			}
			
			public void afterTextChanged(Editable s) {
				// TODO Auto-generated method stub
			}
		});
	}
	
	private void initWritePostTitle(){
		TextView titleView = (TextView) findViewById(R.id.write_post_title);	
		if(mode == FEED_MODE){
			titleView.setText(R.string.your_share);
		}
		else{		
			titleView.setText(R.string.your_comment);
		}
	}
	
	private void initCancelButton(){
		Button cancelButton = (Button) findViewById(R.id.cancel_button);
		cancelButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				finish();
			}
		});
	}
	
	private void initSendButton(){
		Button sendButton = (Button) findViewById(R.id.send_button);
		if(mode == FEED_MODE){
			sendButton.setText(R.string.share);
			sendButton.setOnClickListener(new OnClickListener(){
				public void onClick(View sendButton){
					postSender.setDueTime(selectedDate);
					postSender.setContent(editText.getText().toString());
					postSender.setImages(sourceImage);
					postSender.setTags(tags);
					boolean sendResult = postSender.send();
					deleteCacheFiles();
					showSendResult(sendResult);
					finish();
				}
			});
		}
		else{
			sendButton.setText(R.string.comment);
			sendButton.setOnClickListener(new OnClickListener(){
				public void onClick(View sendButton){
					postSender.setContent(editText.getText().toString());
					NewsFeedItem feedItem = NewsFeedProvider.getInstance(WritePostActivity.this).getNewsFeedItem(position);
					postSender.setNewsFeedId(feedItem.getId());
					boolean sendResult = postSender.send();
					deleteCacheFiles();
					showSendResult(sendResult);
					finish();
				}
			});
		}
	}
	
	private void initEmotionFunction()
	{
		emotionAdapter = new EmotionAdapter(this);
		try {
			emotions = getAssets().list("emotion");
		} catch (IOException e) {
			e.printStackTrace();
		}
		initEmotionPanel();
		initEmotionButton();
	}
	
	private void initEmotionPanel()
	{
		emotionPanel = (GridView)findViewById(R.id.emotion_panel);
		emotionPanel.setAdapter(emotionAdapter);
		emotionPanel.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view, int position, long id){
				Spannable spans = (Spannable)editText.getText();
				String emotionName = emotions[position];
				int postfix = emotionName.lastIndexOf(".");
				emotionName = emotionName.substring(0, postfix);
				emotionName = "[" + emotionName + "]";
				
				int start = editText.getSelectionStart();
				int end = editText.getSelectionEnd();
				editText.getText().replace(Math.min(start, end), Math.max(start, end), emotionName, 0, emotionName.length());
				
			}			
		});		
	}
	
	private void initKeyboardButton(){
		Button keyboardButton = (Button)findViewById(R.id.keyboard_button);
		keyboardButton.setOnClickListener(new OnClickListener(){
			public void onClick(View arg0) {
				// show soft keyboard and hide emotion panel
				emotionPanel.setVisibility(View.GONE);
				inputManager.showSoftInput(editText, 0);
			}			
		});
	}
	
	private void initTagButton(){
		Button tagButton = (Button)findViewById(R.id.tag_button);
		tagButton.setVisibility(View.VISIBLE);
		tagButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				Intent intent = new Intent(WritePostActivity.this, NewsFeedTagActivity.class);
				intent.putStringArrayListExtra(POST_TAGS, tags);
				startActivityForResult(intent, GET_TAGS);
			}
		});
	}
	
	private void initEmotionButton()
	{
		Button emotionButton = (Button)findViewById(R.id.emotion_button);
		emotionButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				// hide soft keyboard				
				inputManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);
				
				if(emotionPanel.getVisibility() == View.GONE)
				{
					emotionPanel.setVisibility(View.VISIBLE);
				}
				else
				{
					emotionPanel.setVisibility(View.GONE);
				}
			}
		});		
	}
	
	private void initPictureFunction(){
		initPictureUploadDialog();
		imagePanel = (LinearLayout)findViewById(R.id.share_post_image);
		Button pictureButton = (Button)findViewById(R.id.picture_button);
		pictureButton.setVisibility(View.VISIBLE);
		pictureButton.setOnClickListener(new OnClickListener() {		
			public void onClick(View v) {
				pictureUploadDialog.show();
			}
		});
	}
	
	private void initPictureUploadDialog(){
		pictureUploadDialog = new Builder(this);
		pictureUploadDialog.setTitle(R.string.upload_picture);
		pictureUploadDialog.setIcon(android.R.drawable.ic_dialog_info);
		String uploadFromFile = getString(R.string.upload_from_file);
		String uploadFromCamera = getString(R.string.upload_from_camera);
		String cancel = getString(R.string.cancel);
		pictureUploadDialog.setItems(new String[]{uploadFromCamera, uploadFromFile, cancel},
				new DialogInterface.OnClickListener() {					
					public void onClick(DialogInterface dialog, int which) {
						if(which == 0){
							Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
							File file = new File(Environment.getExternalStorageDirectory().getPath() + 
											File.separator + UUID.randomUUID().toString() + ".png");
							currentTempImageUri = Uri.fromFile(file);
							intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, currentTempImageUri);
							startActivityForResult(intent, CAMERA_PICTURE);					
						}
						else if(which == 1){
							Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
							intent.setType("image/*");
							String selectPictureSource = getString(R.string.select_picture_source);
							startActivityForResult(Intent.createChooser(intent, selectPictureSource), FILE_PICTURE);
						}
						else{
							dialog.dismiss();
						}
					}
				});
	}
	
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
		if(resultCode == RESULT_OK){
			if(requestCode == FILE_PICTURE){
				if(data != null){
					Uri selectedImageUri = data.getData();
					String filemanagerString = selectedImageUri.getPath();
					String selectedImagePath = getPath(selectedImageUri);
					
					File imageFile = null;
					if(selectedImagePath != null){
						imageFile = new File(selectedImagePath);
					}
					else if(filemanagerString != null){
						imageFile = new File(filemanagerString);
					}
					
					if(imageFile != null){
						Bitmap content = decodeFile(imageFile);
						content = Bitmap.createScaledBitmap(content, IMAGE_SIZE, IMAGE_SIZE, true);
						sourceImage.add(imageFile);
						previewImage.add(content);
						refreshImagePanel();
					}
					else{
						String imageNotFound = getString(R.string.image_not_found);
						Toast.makeText(this, imageNotFound, Toast.LENGTH_LONG).show();
					}
				}
				else{
					String cancelUpload = getString(R.string.cancel_upload);
					Toast.makeText(this, cancelUpload, Toast.LENGTH_LONG).show();
				}
			}
			else if(requestCode == CAMERA_PICTURE){			
				File imageFile = new File(currentTempImageUri.getPath());
				Bitmap content = decodeFile(imageFile);
				content = Bitmap.createScaledBitmap(content, IMAGE_SIZE, IMAGE_SIZE, true);
				sourceImage.add(imageFile);
				previewImage.add(content);
				refreshImagePanel();
			}
			else if(requestCode == GET_TAGS){
				ArrayList tempTags = data.getStringArrayListExtra(POST_TAGS);
				if(tempTags != null){
					tags = tempTags;
					Log.v("return", "" + tags.size());
				}
			}
		}
	}
	
	private String getPath(Uri uri) {
        String[] projection = { MediaStore.Images.Media.DATA };
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if(cursor!=null)
        {
            //HERE YOU WILL GET A NULLPOINTER IF CURSOR IS NULL
            //THIS CAN BE, IF YOU USED OI FILE MANAGER FOR PICKING THE MEDIA
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }
        else return null;
    }
	
	private Bitmap decodeFile(File f) {
        try {
            // decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f), null, o);

            // Find the correct scale value. It should be the power of 2.
            int width_tmp = o.outWidth, height_tmp = o.outHeight;
            int scale = 1;
            while (true) {
                if (width_tmp / 2 < IMAGE_SIZE || height_tmp / 2 < IMAGE_SIZE)
                    break;
                width_tmp /= 2;
                height_tmp /= 2;
                scale++;
            }

            // decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize = scale;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        }
        catch (FileNotFoundException e) {
        }
        return null;
    }
	
	private void refreshImagePanel(){
		imagePanel.removeAllViews();
		LayoutInflater inflater = getLayoutInflater();
		for(int i = 0; i < previewImage.size(); i++){
			RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.write_post_image_preview, null);
			ImageView image = (ImageView) layout.findViewById(R.id.write_post_image);
			image.setImageBitmap(previewImage.get(i));
			
			Button closeButton = (Button) layout.findViewById(R.id.remove_image_button);
			closeButton.setTag(R.id.VIEW_POSITION_TAG, i);
			closeButton.setOnClickListener(new OnClickListener() {			
				public void onClick(View closeButton) {
					int position = (Integer) closeButton.getTag(R.id.VIEW_POSITION_TAG);
					// remove file in cache dir
					if(isInCacheDir(sourceImage.get(position))){
						sourceImage.get(position).delete();
					}
					sourceImage.remove(position);
					previewImage.remove(position);					
					refreshImagePanel();
				}
			});
			imagePanel.addView(layout);
		}
	}
	
	private void initTimeFunction()
	{
		initTimeChooseDialog();
		
		Button timeChooseButton = (Button) findViewById(R.id.timer_button);
		timeChooseButton.setVisibility(View.VISIBLE);
		timeChooseButton.setOnClickListener(new OnClickListener() {			
			public void onClick(View v) {
				timeChooseDialog.show();
			}
		});
	}
	
	private void initTimeChooseDialog()
	{
		timeChooseDialog = new Builder(this);
		timeChooseDialog.setTitle(R.string.save_post_until_when);
		timeChooseDialog.setIcon(R.drawable.ic_dialog_date);
		
		selectedDate = Calendar.getInstance();
		selectedDate.add(Calendar.DATE, 7); // default save 7 days
		datePicker = new DatePicker(this);
		datePicker.init(selectedDate.get(Calendar.YEAR), selectedDate.get(Calendar.MONTH), 
						selectedDate.get(Calendar.DATE), null);
		
		timeChooseDialog.setView(datePicker);
		
		String save = getString(R.string.save);
		timeChooseDialog.setNegativeButton(save, new DialogInterface.OnClickListener() {			
			public void onClick(DialogInterface dialog, int which) {
				saveSelectedDate();
				dialog.dismiss();
			}
		});
	}
	
	private void saveSelectedDate()
	{
		selectedDate.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
	}
	
	private void deleteCacheFiles()
	{
		for(File file : sourceImage){
			// only delete files in cache dir
			if(isInCacheDir(file)){
				file.delete();
			}
		}
	}
	
	private boolean isInCacheDir(File file){
		boolean result = file.getParent().equals(Environment.getExternalStorageDirectory().getPath());
		return result;
	}
	
	private void showSendResult(boolean result){
		if(result == true){
			Toast.makeText(this, getString(R.string.send_success), Toast.LENGTH_SHORT).show();
		}
		else{
			Toast.makeText(this, getString(R.string.send_failure), Toast.LENGTH_SHORT).show();
		}
	}
}
